package com.techysky.util;

import java.io.File;
import java.io.Serializable;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import javax.persistence.EntityManagerFactory;

import org.hibernate.SessionFactory;
import org.hibernate.metadata.ClassMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;




/**
 * 程序启动自动注上下文，
 * @author zhangxu
 *
 */
public class Beans implements Serializable {

	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static final Logger logger=LoggerFactory.getLogger(Beans.class);
	private static ApplicationContext applicationContext;
	private static final String CLASS = ".class";
	private Beans() {}
	
	/**
	 * 
	 * @param context
	 */
	public static void setApplicationContext(ApplicationContext context) {
		applicationContext = context;
	}
	
	/**
	 * 
	 * @return
	 */
	public static ApplicationContext getApplicationContext() {
		return applicationContext;
	}
	
	/**
	 * 
	 * @return
	 */
	public static ConfigurableApplicationContext getConfigurableApplicationContext() {
		return (ConfigurableApplicationContext)applicationContext;
	}
	
	/**
	 * 
	 * @return
	 */
	public static DefaultListableBeanFactory getDefaultListableBeanFactory() {
		return (DefaultListableBeanFactory)getConfigurableApplicationContext().getBeanFactory();
	}
	
	 /**
     * 根据bean的id来查找对象
     * @param id
     * @return
     */
	public static Object getBean(String service) {
		return applicationContext.getBean(service);
	}
	
	/**
     * 根据bean的class来查找对象
     * @param c
     * @return
     */
	public static Object getBean(Class<?> clz) {
		return applicationContext.getBean(clz);
	}
	
	 /**
     * 根据bean的class来查找所有的对象(包括子类)
     * @param clz
     * @return
     */
    @SuppressWarnings("rawtypes")
	public static Map getBeansByClass(Class<?> clz){
        return applicationContext.getBeansOfType(clz);
    }
	
    /**
     * 根据@Service注解返回所有的服务类
     * @return
     */
	public static String[] getServiceBeans(){
		return applicationContext.getBeanNamesForAnnotation(Service.class);
	}
	
	/**
	 * 根据@Repository注解获取所有的持久层服务
	 * @return
	 */
	public static String[] getRepositories(){
		return applicationContext.getBeanNamesForAnnotation(Repository.class);
	}
	
	/**
	 * 获取某个路径下有多少个jar
	 * @param jarPath
	 * @return
	 */
	public static File[] getJars(String jarPath) {
		return new File(jarPath).listFiles(pathname-> pathname.getName().endsWith(".jar"));
	}
	
	/**
	 * 
	 * @param file
	 * @return
	 */
	public static List<Class<?>> loadJar(File file) {
		List<Class<?>> classes = new ArrayList<>();
		try(URLClassLoader classLoader=new URLClassLoader(new URL[]{file.toURI().toURL()});JarFile jarFile=new JarFile(file)) {
		 Enumeration<JarEntry> jars = jarFile.entries();
		 while (jars.hasMoreElements()) {
		    String className = jars.nextElement().getName().replace('/', '.');
		    // 过滤我们出满足我们需求的东西
		    if (className.endsWith(CLASS)) {
		  	    classes.add(classLoader.loadClass(className.substring(0,className.indexOf(CLASS))));
		    }
		  }
		} catch (Exception e) {
			logger.debug(String.format("加载 jar失败!%n"));
		}
	  return classes;
	}
	
	/**
	 * 加载jar下的class
	 * @param jarPath
	 * @return
	 */
	public static List<Class<?>> loadJars(String jarPath){
		List<Class<?>> classes = new ArrayList<>();
		File[] jarFiles=getJars(jarPath);
		if(!ObjectUtils.isEmpty(jarFiles)) {
			for (File file : jarFiles) {
				try(URLClassLoader classLoader=new URLClassLoader(new URL[]{file.toURI().toURL()});JarFile jarFile=new JarFile(file)) {
				 Enumeration<JarEntry> jars = jarFile.entries();
				 while (jars.hasMoreElements()) {
				    String className = jars.nextElement().getName().replace('/', '.');
				    // 过滤出满足我们需求的东西
				    if (className.endsWith(CLASS)) {
				  	    classes.add(classLoader.loadClass(className.substring(0,className.indexOf(CLASS))));
				    }
				  }
				} catch (Exception e) {
					logger.debug(String.format("加载 jar失败!%n"));
				}
			}
		}
		return classes;   
	}
	
	/**
	 * 
	 * @param jarPath jar包完整路径
	 * @param jar 如果该值不为空则一次加载一个jar
	 */
	public static void registerBean(String jarPath,String jar) {
		 DefaultListableBeanFactory beanFactory = getDefaultListableBeanFactory();
	     List<Class<?>> classes;
		 if(!ObjectUtils.isEmpty(jar)) {
			classes=loadJars(jarPath);
		 }else {
			classes=loadJar(new File(jarPath,jar));
		 }
		 classes.forEach(clz->{
			 BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clz);
		     if(null!=getServiceName(clz))
		     beanFactory.registerBeanDefinition(getServiceName(clz),beanDefinitionBuilder.getRawBeanDefinition());
		 });
	}
	
	/**
	 * 
	 * @param file
	 */
	public static void registerBean(File file) {
		 DefaultListableBeanFactory beanFactory = getDefaultListableBeanFactory();
	     loadJar(file).forEach(clz->{
			     if(null!=getServiceName(clz)) {
			    	 BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clz);
				     beanFactory.registerBeanDefinition(getServiceName(clz),beanDefinitionBuilder.getRawBeanDefinition());
			     }
			 });
	}
	

	/**
	 * 获取项目中所哦鱼的
	 * @return
	 */
	public static List<Map<String, String>> getEntity(){
		List<Map<String,String>> result = new ArrayList<>();
		EntityManagerFactory emf=(EntityManagerFactory) getBean("entityManagerFactory");
		SessionFactory sessionFactory=emf.unwrap(SessionFactory.class);
		Map<String,ClassMetadata> map=sessionFactory.getAllClassMetadata();
		for (Map.Entry<String,ClassMetadata> entry : map.entrySet()) { 
			Map<String,String> ma = new HashMap<>();
			ma.put("key", entry.getKey().substring(entry.getKey().lastIndexOf('.')+1));
			ma.put("value", entry.getKey());
			ma.put(entry.getKey().substring(entry.getKey().lastIndexOf('.')+1), entry.getKey());
			result.add(ma);
		}
		return result;
	}
	
	/**
	 * 根据实体名获取实体类
	 * @param entityName
	 * @return
	 */
	public static Class<?> getEntityClass(String entityName) {
		List<Map<String,String>> entities = getEntity();
		for (Map<String, String> entity : entities) {
			if(!ObjectUtils.isEmpty(entity.get(entityName))) {
				try {
					return Class.forName(entity.get(entityName));
				} catch (ClassNotFoundException e) {
					logger.debug(String.format("实体映射失败!%n"));
				}
			   }
		}
		return null;
	}
	
	/**
	 * 
	 * @param clz
	 * @return
	 */
	public static String getServiceName(Class<?> clz) {
		try {
			Service service=clz.newInstance().getClass().getAnnotation(Service.class);
			if(service!=null)
				return service.value();
		} catch (InstantiationException|IllegalAccessException e) {
			logger.debug(String.format("服务无效!%n"));
		} 
		return null;
	}
}
